﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Microsoft.SharePoint.Administration;
using System.Windows.Forms;
using Microsoft.SharePoint;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using eAPIs=Microsoft.Office.Interop.Excel;

namespace SharePointUsers
{
    public static class Reporter
    {
        #region Static Members
        public static int CURRENT_VER_MAJOR = 1;
        public static int CURRENT_VER_MINOR = 0;
        public static string PROP_NAME_SPLITTER = " ";
        #endregion
        public static DataTable ExecuteReport(Report reportObj, TreeView SPObjTree)
        {
            DataTable Report = ProcessReport(SPObjTree, reportObj);
            return Report;
        }

        private static List<string> ParseReportQuery(string Query)
        {
            string[] SPObjects = Query.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
            List<string> PathParts = new List<string>(SPObjects.Length);

            foreach (string level in SPObjects)
            {
                PathParts.Add(level.ToLower());
            }
            return PathParts;
        }
        public static bool HasQueryFor(Dictionary<SPType, Property[]> QueryParts, SPType spType)
        {
            return QueryParts.ContainsKey(spType) && QueryParts[spType] != null && QueryParts[spType].Length > 0;
        }
        public static DataTable CreateDataTable(Dictionary<SPType, Property[]> Query)
        {
            DataTable ReportStructure = new DataTable("Report");
            foreach (var QueryParts in Query)
            {
                foreach (Property prop in QueryParts.Value)
                {
                    if(string.IsNullOrEmpty(prop.DisplayName))
                        ReportStructure.Columns.Add(QueryParts.Key.ToString() + PROP_NAME_SPLITTER + prop.Name);
                    else
                        ReportStructure.Columns.Add(prop.DisplayName);
                }

            }
            return ReportStructure;
        }
        private static List<string> GetObjectQueryParts(Dictionary<SPType, Property[]> Query, SPType ObjType)
        {
            List<string> queryParts = new List<string>();
            //Make sure the query object has the requested sp object properties
            if (Query.ContainsKey(ObjType))
            {
                string ObjName = ObjType.ToString();
                Property[] Properties = Query[ObjType];
                queryParts = new List<string>(Properties.Length);
                foreach (Property Prop in Properties)
                {
                    if(string.IsNullOrEmpty(Prop.DisplayName))
                        queryParts.Add(ObjName + PROP_NAME_SPLITTER + Prop.Name);
                    else
                        queryParts.Add(Prop.DisplayName);
                }

            }
            return queryParts;
        }
        private static void UpdatePropertyValue(Dictionary<string, string> Values, string FieldName, string Value)
        {
            if (Values.ContainsKey(FieldName))
            {
                Values[FieldName] = Value;
            }
            else
            {
                Values.Add(FieldName, Value);
            }
        }
        private static void FlushPropertyBaseValues(DataTable ReportData, DataRow record, Dictionary<string, string> BaseDataRow)
        {
            //Add all values to the record
            record = ReportData.NewRow();
            foreach (var recordElements in BaseDataRow)
            {
                record[recordElements.Key] = recordElements.Value;
            }
            ReportData.Rows.Add(record);
        }
        public static bool IsPropertyDisplayNameUniqueAndValid(Report ReportObj,string PropertyName, string DisplayName)
        {
            bool Unique = false;
            if(string.IsNullOrEmpty(DisplayName)) return Unique;
            //Validate other properties
            foreach (var PropType in ReportObj.Query.Keys)
            {
                foreach (var Prop in ReportObj.Query[PropType])
                {
                    //Skip the property itself
                    if (string.Compare(Prop.Name, PropertyName, true) == 0) continue;
                    if (Prop.DisplayName == DisplayName)
                    {
                        return false;
                    }
                }
            }

            return true;
        }
        public static bool IsPropertyDisplayNameUniqueAndValid(HashSet<string> Properties, string DisplayName)
        {
            bool Unique = false;
            if (string.IsNullOrEmpty(DisplayName)) return Unique;
            //Validate other properties
            if (Properties.Contains(DisplayName))
                return false;

            return true;
        }
        private static bool ListContainsStringIgnoreCase(List<string> list,string keyword)
        {
            return list.FindAll(s => s.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0).Count > 0;
        }
        public static DataTable ProcessReport(TreeView SPObjTree, Report ReportObj)
        {
            bool FarmPropertiesQuery = HasQueryFor(ReportObj.Query, SPType.Farm);
            bool WebApplicationsQuery = HasQueryFor(ReportObj.Query, SPType.WebApplication);
            bool ContentDBQuery = HasQueryFor(ReportObj.Query, SPType.ContentDatabase);
            bool SiteCollectionsQuery = HasQueryFor(ReportObj.Query, SPType.SiteCollection);
            bool WebQuery = HasQueryFor(ReportObj.Query, SPType.Site);

            List<string> WebAppScope = ReportObj.Scope[SPType.WebApplication];
            List<string> ContentDbScope = ReportObj.Scope[SPType.ContentDatabase];
            List<string> SiteCollectionScope = ReportObj.Scope[SPType.SiteCollection];
            List<string> SiteScope = ReportObj.Scope[SPType.Site];
            bool HasWebApplicationScope = WebAppScope.Count > 0;
            bool HasContentDbScope = ContentDbScope.Count > 0;
            bool HasSiteCollectionScope = SiteCollectionScope.Count > 0;
            bool HasWebScope = SiteScope.Count > 0;
            //Find the lowest query object requested
            SPType LowestTypeQuried = SPType.Undefined;
            if (FarmPropertiesQuery)
            {
                LowestTypeQuried = SPType.Farm;
            }
            if (WebApplicationsQuery)
            {
                LowestTypeQuried = SPType.WebApplication;
            }
            if (ContentDBQuery)
            {
                LowestTypeQuried = SPType.ContentDatabase;
            }
            if (SiteCollectionsQuery)
            {
                LowestTypeQuried = SPType.SiteCollection;
            }
            if (WebQuery)
            {
                LowestTypeQuried = SPType.Site;
            }

            //Create Data structure to store the report data
            DataTable Report = CreateDataTable(ReportObj.Query);
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;
            if (CurrentFarm == null || FarmObj == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));

            DataRow record = null;
            //Get farm report data
            SPObject farmObj = null;
            if (FarmPropertiesQuery)
            {
                farmObj = SPdalHelper.PopulateFarm(FarmObj, true);
                //RequestFarmProps = GetObjectQueryParts(ReportObj.Query, SPType.Farm);

            }


            SPObject SPObj = null;


            Dictionary<string, string> BaseDataRow = new Dictionary<string, string>();
            if (FarmPropertiesQuery)
            {
                foreach (Property Prop in ReportObj.Query[SPType.Farm])
                {
                    UpdatePropertyValue(BaseDataRow, Prop.DisplayName, farmObj.Properties[Prop.Name.ToLower()]);
                }
            }
            if (LowestTypeQuried == SPType.Farm)
                FlushPropertyBaseValues(Report, record, BaseDataRow);
            else
            {
                foreach (SPWebApplication WebApp in CurrentFarm.WebApplications)
                {
                       
                        if (WebApplicationsQuery)
                        {
                            if ((HasWebApplicationScope && ListContainsStringIgnoreCase(WebAppScope,WebApp.Id.ToString()) || !HasWebApplicationScope))
                            {
                                SPObj = SPdalHelper.PopulateApplication(WebApp, true, true);
                                foreach (Property Prop in ReportObj.Query[SPType.WebApplication])
                                {
                                    UpdatePropertyValue(BaseDataRow, Prop.DisplayName, SPObj.Properties[Prop.Name.ToLower()]);
                                }
                            }
                            else
                                continue;
                        }
                    
                    if (LowestTypeQuried == SPType.WebApplication)
                    {
                        FlushPropertyBaseValues(Report, record, BaseDataRow);
                        continue;
                    }
                    foreach (SPContentDatabase ContentDB in WebApp.ContentDatabases)
                    {
                        if (ContentDBQuery)
                        {
                            if ((HasContentDbScope && ListContainsStringIgnoreCase(ContentDbScope,ContentDB.Id.ToString())) || !HasContentDbScope)
                            {
                                SPObj = SPdalHelper.PopulateContentDB(ContentDB, true);
                                foreach (Property Prop in ReportObj.Query[SPType.ContentDatabase])
                                {
                                    UpdatePropertyValue(BaseDataRow, Prop.DisplayName, SPObj.Properties[Prop.Name.ToLower()]);
                                }
                            }
                            else
                                continue;
                        }
                        if (LowestTypeQuried == SPType.ContentDatabase)
                        {
                            FlushPropertyBaseValues(Report, record, BaseDataRow);
                            continue;
                        }
                        foreach (SPSite Site in ContentDB.Sites)
                        {
                            ////Add all values to the record
                            //record = Report.NewRow();
                            //foreach (var recordElements in BaseDataRow)
                            //{
                            //    record[recordElements.Key] = recordElements.Value;
                            //}

                            if (SiteCollectionsQuery)
                            {
                                if ((HasSiteCollectionScope && ListContainsStringIgnoreCase(SiteCollectionScope,Site.Url)) || !HasSiteCollectionScope)
                                {
                                    SPObj = SPdalHelper.PopulateSiteCollection(Site, true);
                                    foreach (Property Prop in ReportObj.Query[SPType.SiteCollection])
                                    {
                                        //record[Prop.DisplayName] = SPObj.Properties[Prop.Name.ToLower()];
                                        UpdatePropertyValue(BaseDataRow, Prop.DisplayName, SPObj.Properties[Prop.Name.ToLower()]);

                                    }
                                }
                                else
                                    continue;
                            }
                            if (LowestTypeQuried == SPType.SiteCollection)
                            {
                                FlushPropertyBaseValues(Report, record, BaseDataRow);
                                continue;
                            }
                            //Report.Rows.Add(record);

                            /*
                            foreach (SPWeb Web in Site.AllWebs)
                            {
                                //if (WebQuery)
                                //{
                                //    SPObj = SPdalHelper.PopulateWwe(Site, true);
                                //    foreach (string Prop in RequestSiteProps)
                                //    {
                                //        string propName = Prop.Split('.')[1];
                                //        record[Prop] = SPObj.Properties[propName];
                                //    }
                                //}
                            }
                             */
                        }
                    }

                }
            }
            return Report;

        }
        private static TreeNode GetObjectNode(TreeView Tree, SPType NodeType)
        {
            TreeNode Node = null;
            if (Tree == null || Tree.Nodes.Count <= 0) return Node;
            switch (NodeType)
            {
                case SPType.Farm:
                    return Tree.Nodes[0];
                case SPType.WebApplication:
                    break;
                case SPType.SiteCollection:
                    break;
                case SPType.Site:
                    break;
                case SPType.List:
                    break;
                case SPType.Item:
                    break;
                case SPType.Group:
                    break;
                case SPType.User:
                    break;
                case SPType.ContentDatabase:
                    break;
                case SPType.Feature:
                    break;
                case SPType.Collection:
                    break;
                default:
                    break;
            }
            return Node;
        }
        public static string GetIdentifierPropertyName(SPType ObjectType)
        {
            string PropertyName = "Id";
            switch (ObjectType)
            {
                case SPType.Farm:
                    break;
                case SPType.WebApplication:
                    break;
                case SPType.SiteCollection:
                    return "Url";
                case SPType.Site:
                    return "Url";
                case SPType.List:
                    return "Title";
                case SPType.Item:
                    break;
                case SPType.Group:
                    break;
                case SPType.User:
                    break;
                case SPType.ContentDatabase:
                    break;
                case SPType.Feature:
                    break;
                case SPType.Collection:
                    break;
                case SPType.Undefined:
                    break;
                default:
                    break;
            }
            return PropertyName;
        }
        private static void LoadContentDbs(TreeView SPObjTree, List<string> PathParts)
        {
            int ReportDepth = PathParts.Count;
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;
            if (CurrentFarm == null || FarmObj == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));

            //Report on more than the farm object
            if (ReportDepth > 1)
            {
                switch (ReportDepth)
                {
                    case 2:
                        foreach (SPWebApplication WebApp in CurrentFarm.WebApplications)
                        {

                        }
                        break;
                    case 3:
                        break;
                    default:
                        break;
                }
            }




        }
        private static DataTable GenerateDataStructure()
        {
            DataTable DataStructure = new DataTable("Databases");
            DataStructure.Columns.Add("ID");
            DataStructure.Columns.Add("Web Application");
            DataStructure.Columns.Add("DB Name");
            DataStructure.Columns.Add("Type");
            DataStructure.Columns.Add("Total Sites Count");
            DataStructure.Columns.Add("Site Collection");
            DataStructure.Columns.Add("Status");
            DataStructure.Columns.Add("Size");
            return DataStructure;
        }
        private static DataTable GenerateReportData(TreeView SPObjTree)
        {
            DataTable Databases = GenerateDataStructure();


            //Check if the farm node is loaded or not
            if (SPObjTree.Nodes.Count == 0) return Databases;
            SPWebService CurrentFarm = SPWebService.ContentService;
            int ID = 1;
            foreach (TreeNode App in SPObjTree.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                // The content dbs are not loaded yet
                if (App.Nodes.Count <= 0)
                {
                    //Load the content dbs
                    //LoadContentDb(CurrentFarm.WebApplications[App.Text], App);
                }
                //Iterate through content databases
                foreach (TreeNode contentDb in App.Nodes)
                {
                    foreach (TreeNode sc in contentDb.Nodes)
                    {
                        try
                        {
                            DataRow Dbrecord = Databases.NewRow();
                            Dbrecord["ID"] = ID++;
                            Dbrecord["Web Application"] = SPdalHelper.GetSPObjectProperty(App, "Name");
                            Dbrecord["DB Name"] = SPdalHelper.GetSPObjectProperty(contentDb, "Name");
                            Dbrecord["Type"] = "Content Database";
                            double Size = double.Parse(SPdalHelper.GetSPObjectProperty(contentDb, "DiskSizeRequired"));
                            Size = Size / (Convert.ToDouble(1024) * Convert.ToDouble(1024) * Convert.ToDouble(1024));
                            Dbrecord["Size"] = Math.Round(Size, 3);
                            Dbrecord["Total Sites Count"] = SPdalHelper.GetSPObjectProperty(contentDb, "CurrentSiteCount");
                            Dbrecord["Site Collection"] = SPdalHelper.GetSPObjectProperty(sc, "Url");
                            Dbrecord["Status"] = SPdalHelper.GetSPObjectProperty(contentDb, "Status");
                            Databases.Rows.Add(Dbrecord);
                        }
                        catch
                        {
                        }

                    }

                }
            }
            return Databases;
        }
        public static void SaveReportObject(Report reportObj, string FileName)
        {
            XmlSerializer mySerializer = new
            XmlSerializer(typeof(Report));
            // To write to a file, create a StreamWriter object.
            StreamWriter myWriter = new StreamWriter(FileName);
            mySerializer.Serialize(myWriter, reportObj);
            myWriter.Close();

        }
        public static Report LoadReportObject(string FileName)
        {
            Report reportObj = null;
            // Construct an instance of the XmlSerializer with the type
            // of object that is being deserialized.
            XmlSerializer mySerializer =
            new XmlSerializer(typeof(Report));
            // To read the file, create a FileStream.
            using (FileStream myFileStream =
            new FileStream(FileName, FileMode.Open))
            {
                // Call the Deserialize method and cast to the object type.
                reportObj = (Report)
                mySerializer.Deserialize(myFileStream);
                myFileStream.Close();
                if (reportObj.Properties == null)
                    reportObj.Properties = new SerializableDictionary<string, string>();
            }
            return reportObj;
        }
        public static void SaveToExcel(DataTable ReportData, string FileName)
        {

            eAPIs.ApplicationClass excel = new eAPIs.ApplicationClass();
            eAPIs.Workbook workbook = excel.Application.Workbooks.Add(true);
            //Adding column headings
            int iCol = 0;
            int iRow = 0;
            foreach (DataColumn Col in ReportData.Columns)
            {
                iCol++;
                excel.Cells[1, iCol] = Col.ColumnName;
            }
            foreach (DataRow record in ReportData.Rows)
            {
                iRow++;
                // add each row's cell data...
                iCol = 0;
                foreach (DataColumn Col in ReportData.Columns)
                {
                    iCol++;
                    excel.Cells[iRow + 1, iCol] = record[Col].ToString();
                }
            }
            // Global missing reference for objects we are not defining...
            object missing = System.Reflection.Missing.Value;
            // If wanting to Save the workbook...   
            workbook.SaveAs(FileName, eAPIs.XlFileFormat.xlWorkbookDefault, missing, missing, false, false, eAPIs.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing);
            // If wanting to make Excel visible and activate the worksheet...
            excel.Visible = true;
            eAPIs.Worksheet worksheet = (eAPIs.Worksheet)excel.ActiveSheet;
            excel.Rows.EntireRow.AutoFit();
            excel.Columns.EntireColumn.AutoFit();
            workbook.Save();
            ((eAPIs._Worksheet)worksheet).Activate();
        }


    }

}

    


